package compiler.code_generator;

public class MinijavaFilePattern
{
    private int labelIndex = 0;

    public String produceMainEntry(String className, String argName, String programBody)
    {
        return ".class public " + className + "\n" +
                    ".super java/lang/Object\n" +
                    "\n" +
                    ".method public <init>()V\n" +
                    "   aload_0\n" +
                    "   invokenonvirtual java/lang/Object/<init>()V\n" +
                    "   return\n" +
                    ".end method\n" +
                    "\n" +
                    ".method public static main([Ljava/lang/String;)V\n" +
                    "    .limit stack 255\n" +
                    programBody + "\n" +
                    "    return\n" +
                    ".end method";
    }

    public String produceLocalsLimit(Integer localsCount)
    {
        return ".limit locals " + localsCount.toString() + "\n";
    }

    public String produceLessThan()
    {
        int labelsIndex = labelIndex++;
        return  "if_icmplt Label" + labelsIndex + "\n" +
                "bipush 0\n" +
                "goto Endcmp" + labelsIndex + "\n" +
                "Label" + labelsIndex + ":\n" +
                "bipush 1\n" +
                "Endcmp" + labelsIndex + ":\n";
    }

    public String produceWhileStatement(String conditionStr, String statementStr)
    {
        int labelsIndex = labelIndex++;
        return "WhileBegin" + labelsIndex + ":\n" +
               conditionStr +
               "ifeq WhileEnd" + labelsIndex + "\n" +
               statementStr +
               "goto WhileBegin" + labelsIndex + "\n" +
               "WhileEnd" + labelsIndex + ":\n";
    }

    public String produceIfStatement(String condition, String ifStatement, String elseStatement)
    {
        int labelsIndex = labelIndex++;
        return  condition +
                "ifne IfLabel" + labelsIndex + "\n" +
                elseStatement +
                "goto IfEnd" + labelsIndex + "\n" +
                "IfLabel" + labelsIndex + ":\n" +
                ifStatement +
                "IfEnd" + labelsIndex + ":\n";
    }

    public String storeInt(Integer address)
    {
        return "istore " + address.toString() + "\n";
    }

    public String loadInt(Integer address)
    {
        return "iload " + address.toString() + "\n";
    }

    public String storeRef(Integer address)
    {
        return "astore " + address.toString() + "\n";
    }

    public String loadRef(Integer address)
    {
        return "aload " + address.toString() + "\n";
    }

    public String storeIntIntoArray()
    {
        return "iastore\n";
    }

    public String loadIntFromArray()
    {
        return "iaload\n";
    }

    public String newIntArray()
    {
        return "newarray int\n";
    }

    public String printBool(String printArgumentCode)
    {
        return "getstatic java/lang/System/out Ljava/io/PrintStream;\n" +
                printArgumentCode + "\n" +
               "invokestatic java/lang/String/valueOf(Z)Ljava/lang/String;\n" +
               "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V\n";
    }

    public String printInt(String printArgumentCode)
    {
        return "getstatic java/lang/System/out Ljava/io/PrintStream;\n" +
                printArgumentCode + "\n" +
               "invokestatic java/lang/String/valueOf(I)Ljava/lang/String;\n" +
               "invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V\n";
    }

    public String add()
    {
        return "iadd\n";
    }

    public String sub()
    {
        return "isub\n";
    }

    public String mul()
    {
        return "imul\n";
    }

    public String div()
    {
        return "idiv\n";
    }

    public String mod()
    {
        return "irem\n";
    }

    public String and()
    {
        return "iand\n";
    }

    public String or()
    {
        return "ior\n";
    }

    public String negate()
    {
        return "ineg\n";
    }

    public String not()
    {
        return  pushByte(1) + "ixor\n";
    }

    public String pushInt(Integer intValue)
    {
        return "ldc " + intValue.toString() + "\n";
    }

    public String pushByte(Integer intValue)
    {
        return "bipush " + intValue.toString() + "\n";
    }
}
